/**
 * 
 */
package com.glodon.paas.account.dao.redis;

import java.util.Set;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;

import com.glodon.paas.account.dao.OAuthTokenDao;
import com.glodon.paas.account.dao.domain.OAuthTokenEntity;

/**
 * @author hankl
 * 
 */
public class OAuthTokenDaoRedisImpl implements OAuthTokenDao {
	public static final String USERID_PREFIX = "uid:";
	public static final String DEFAULT_OAUTH_PREFIX = "oauth:token:"; // "oauth:access:token:";
	public static final String DEFAULT_REQUEST_PREFIX = "oauth:request:token:";
	private final String keyPrefix;
	private final RedisTemplate<String, OAuthTokenEntity> template;
	private final ValueOperations<String, OAuthTokenEntity> operations;
	private JedisPool pool;

	private int requestTokenValiditySeconds = 600;
	private int accessTokenValiditySeconds = 60 * 60 * 24 * 180;

	public void setPool(JedisPool pool) {
		this.pool = pool;
	}

	public void setRequestTokenValiditySeconds(int requestTokenValiditySeconds) {
		this.requestTokenValiditySeconds = requestTokenValiditySeconds;
	}

	public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {
		this.accessTokenValiditySeconds = accessTokenValiditySeconds;
	}

	public OAuthTokenDaoRedisImpl(String keyPrefix,
			RedisTemplate<String, OAuthTokenEntity> template) {
		this.keyPrefix = keyPrefix;
		this.template = template;
		this.operations = template.opsForValue();
	}

	@Override
	public OAuthTokenEntity readToken(String tokenValue) {
		return operations.get(DEFAULT_OAUTH_PREFIX + tokenValue);
	}

	@Override
	public void saveToken(OAuthTokenEntity token) {
		final Jedis jedis = pool.getResource();
		try {
			final String key;
			key = DEFAULT_OAUTH_PREFIX + token.getValue();
			Transaction transaction = jedis.multi();
			transaction.set(key.getBytes(),
					new JdkSerializationRedisSerializer().serialize(token));	

			if (token.isAccessToken()) {
				transaction.sadd(USERID_PREFIX+token.getUserId(), token.getValue());
				transaction.expire(key, accessTokenValiditySeconds);
			} else {
				transaction.expire(key, requestTokenValiditySeconds);
			}

			transaction.exec();

		} finally {
			pool.returnResource(jedis);
		}
	}

	@Override
	public OAuthTokenEntity removeToken(String tokenValue) {
		String key = DEFAULT_OAUTH_PREFIX+tokenValue;
		final Jedis jedis = pool.getResource();
		OAuthTokenEntity t  = operations.get(key);
		try{		
			Transaction transaction = jedis.multi();			
			
			if(t != null){
				//template.delete(key);
				transaction.del(key);
				transaction.srem(USERID_PREFIX+t.getUserId(), tokenValue);
				transaction.exec();
			}	
		}finally{
			pool.returnResource(jedis);
		}
	
		return t;
	}

	@Override
	public void removeToken(String consumerKey, String userId) {
		final Jedis jedis = pool.getResource();
		String uidKey = USERID_PREFIX+userId;
		try{
			Set<String> tokenSet = jedis.smembers(uidKey);
			Transaction transaction = jedis.multi();		
			int count=0;
			for(String tokenValue: tokenSet)
			{
				OAuthTokenEntity entity = readToken(tokenValue);
				if(entity!=null && entity.getConsumerKey().equals(consumerKey)){
					transaction.del(DEFAULT_OAUTH_PREFIX+tokenValue);
					transaction.srem(uidKey, tokenValue);
					count++;
				}				
			}
			if(tokenSet.size()==count){
				transaction.del(uidKey);
			}
			
			transaction.exec();
			
		}finally{
			pool.returnResource(jedis);
		}	

	}

	@Override
	public String insert(OAuthTokenEntity entity) {
		saveToken(entity);
		return entity.getValue();
	}

	@Override
	public OAuthTokenEntity get(String id) {
		return readToken(id);
	}

	@Override
	public int delete(String id) {
		removeToken(id);
		return 1;
	}

	private String getKey(String pattern) {
		String keyPattern = "*" + pattern;
		Jedis jedis = pool.getResource();
		String key = "";
		try {
			Set<String> keySet = jedis.keys(keyPattern);
			if (!keySet.isEmpty()) {
				key = keySet.iterator().next();
			}
		} finally {
			pool.returnResource(jedis);
		}
		return key;
	}

	private Set<String> getKeys(String pattern) {
		String keyPattern = "*" + pattern + "*";
		Jedis jedis = pool.getResource();
		Set<String> keySet;
		try {
			keySet = jedis.keys(keyPattern);
		} finally {
			pool.returnResource(jedis);
		}

		return keySet;

	}

}
